#include "verilated.h" //Defines common routines
#include "Vtop.h"
#include <cstdio>
#include <ctime>
#include <stdint.h>
#include "aesencode.h"
#include "Caes.h"
# include <cstring>
unsigned int mytime = 0;
VerilatedVcdC *fp;
Vtop *dut_ptr; 

uint8_t single_cmp(uint32_t* key_u32,uint32_t* txt_u32){
    uint32_t Vaes_out[AES_SPLITE];
    uint32_t Caes_out[AES_SPLITE];
    uint8_t key_u8[16];
    uint8_t txt_u8[16];
    // printf("[Verilog Model]");
    aes_128_caculate(txt_u32,key_u32,Vaes_out);

    u32_to_u8(key_u32, key_u8, AES_SPLITE);
    u32_to_u8(txt_u32, txt_u8, AES_SPLITE);
    // printf("[-CPP-   Model]");
    once_encrypt(key_u8, txt_u8);
    u8_to_u32(txt_u8, Caes_out, AES_SPLITE);

    //txt_u8 <==> out
    if (0 == memcmp(Vaes_out, Caes_out, AES_SPLITE)){
        printf("==>\033[31m\033[1mPASS\033[0m\n");
        printf("==>The key is:");print128(key_u32);printf("\n");
        printf("==>The txt is:");print128(txt_u32);printf("\n");
        printf("==>The out is:");print128(Caes_out);printf("\n");
        printf("==>\033[33mNow cycle is:%d\n\033[37m",mytime/2);
        return 1;
    }else{
        printf("==>\033[31m\033[1m FAIL\033[0m\n");
        printf("==>The key is:");print128(key_u32);printf("\n");
        printf("==>The txt is:");print128(txt_u32);printf("\n");
        printf("==>Right out is:");print128(Caes_out);printf("\n");
        printf("==>Wrong out is:\033[31m\033[1m");print128(Vaes_out);printf("\033[0m\n");
        printf("\033[33m==>Now cycle is:%d\n\033[37m",mytime/2);
        return 1;
    }
}

int main()
{
    dut_ptr = new Vtop; //instantiating module top

#ifdef VM_TRACE
    ////// !!!  ATTENTION  !!!//////
    //  Call Verilated::traceEverOn(true) first.
    //  Then create a VerilatedVcdC object.
    Verilated::traceEverOn(true);
    printf("Enabling waves ...\n");
    fp = new VerilatedVcdC; //instantiating .vcd object
    dut_ptr->trace(fp, 99); //trace 99 levels of hierarchy
    fp->open("vlt_dump.vcd");
    fp->dump(mytime++);
#endif

    dut_ptr->AHB_HRESETn = 0;
    delay_cycle(2);
    dut_ptr->AHB_HRESETn = 1;
    uint32_t key_u32[AES_SPLITE] = {0x2B7E1516, 0x28AED2A6, 0xABF71588, 0x09CF4F3C}; //{0xAAAABBBB,0xCCCCDDDD,0x11112222,0x33334444};
    uint32_t txt_u32[AES_SPLITE] = {0x3243F6A8, 0x885A308D, 0x313198A2, 0xE0370734}; //{0x11111111,0x11111111,0x11112222,0x33334444};
    uint32_t out_u32[AES_SPLITE];

    
    printf("===============AES TEST START========================\n");
    int use_time = mytime;
    single_cmp(txt_u32,key_u32);
    use_time -= mytime;
    printf("==>use cycle is %d\r\n",-use_time/2); 
    // printf("==> Encode:\n");
    // printf("AES in  is :");print128(txt_u32);printf("\r\n");
    // printf("AES key is :");print128(key_u32);printf("\r\n");
    // printf("AES out is :");print128(out_u32);printf("\r\n");
    printf("===============AES TEST END==========================\n");


    // int test_num = 10;
    // printf("please input test number:");
    // scanf("%d",&test_num);

    // printf("------------------AES TEST START---------------------\n ");
    // int k=0;int start;

    // for(int i=0;i<test_num;i++){
    //     srand((int)(time(NULL)));
    //     for(int j=0;j<AES_SPLITE;j++){
    //         key_u32[j] = rand() & 0xFFFFFFFF;
    //         txt_u32[j] = rand() & 0xFFFFFFFF;
    //     }

    //     if(single_cmp(key_u32,txt_u32))
    //         return 1;
    //     else 
    //         k++;

    //     if(k%50 == 0){
    //         printf("[%5d / %5d] PASS\n ",k,test_num);
    //     }else if(k == test_num)
    //         printf("[%5d / %5d] PASS\n ",k,test_num);
    // }    

    // printf("------------------AES TEST END-----------------------\n");

#ifdef VM_TRACE
    fp->close();
    delete fp;
#endif

    delete dut_ptr;

    return 0;
}